/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
 */

package com.jinhe.tss.core.cachepool;

import com.jinhe.tss.core.exception.BusinessException;

/** 
 * <p> ReusablePool.java </p> 
 * 
 * <p></p>缓存项要求可重复利用的，即缓存项的value对象实现Reusable接口。
 * <p></p>适合用于线程池，连接池，任务载体池等。
 * <p></p>在该类中，缓存池中的对象由算法类的create()方法生成，
 * <p></p>在缓存池初始化以及check-out时对象不够的情况下创建新的对象。
 * 
 * @author Jon.King 2006-12-28
 */
public class ReusablePool extends ObjectPool {
    /**
     * 将元素从free池中取出，放入using池中，并返回该元素。</p><p>
     * 
     * 如果没有空置的元素可以获取，则一个新的元素将会创建出来，除非到了池的上限值。</p><p>
     * 如果一个空置的元素是错误的，它将被移出对象池，将会重新获取另外一个元素出来。</p><p>
     * @return 
     *       池中的元素，如果没有可用对象返回null
     * @exception PoolException
     *       创建对象时出错则抛异常
     */
    protected Cacheable checkOut() {
        Cacheable item = null;
        if (getFree().size() > 0){
            boolean valid;
            //循环取，直到取出一个正确的或者free  List为空为止
            do {
                item  = remove();
                if( valid = getArithmetic().isValid(item) ) {
                    break;
                } else {
                    getArithmetic().destroy(item);
                    log.info("将验证没通过的缓存项: " + item + " 销毁");
                }
            } while(getFree().size() > 0);
            
            if (!valid) item = null;
        }
        boolean isHit = (item != null); //如果对象是从池中取出的，则命中率 hit＋＋

        // 如果free池中取不到，如果池中缓存项个数还没达到池的最大值，则新建一个
        if (item == null){
            int maxSize = getCacheStrategy().getPoolSize().intValue();
            if (getSize() < maxSize  ||  maxSize == 0){
                item = getArithmetic().create(getCacheStrategy().getCyclelife());
                if (!getArithmetic().isValid(item)){
                    String errorInfo = "池 （" + getName() + "） 不能创建一个新的有效的缓存项。";
                    log.debug(errorInfo);
                    throw new BusinessException(errorInfo);
                }
            }
        }
        //如果一个有效的缓存项已经得到或者创建出来，将它放入using集合中
        if (item != null){
            item.addHit();
            item.updateAccessed();
            
            getUsing().put(item.getKey(), item);
            
            addRequests();
            if(isHit) addHits();
            
            firePoolEvent(ObjectPoolEvent.CHECKOUT);        
        }
        log.debug("Check out - (池点击率 = " + getHitRate() + "%)" + (item == null ? " - 无对象返回" : ""));
        return item;
    }
}

